package com.xjscrm.server.common.util;

import com.xjscrm.common.utils.ww.AesException;
import com.xjscrm.common.utils.ww.WXBizMsgCrypt;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import javax.servlet.http.HttpServletRequest;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @author lucher.chen create in 2024/3/1 18:25
 */
@Slf4j
public class QyWxTools {

    /**
     * 验证回调URL
     *
     * @param request
     * @return
     */
    public static String verificationUrl(HttpServletRequest request, String sToken, String sCorpID, String sEncodingAESKey) {
        log.info("=========验证URL有效性开始=========sToken={}, sCorpID={}, sEncodingAESKey={}",sToken, sCorpID, sEncodingAESKey);
        String sEchoStr = ""; //需要返回的明文
        try {
            WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(sToken, sEncodingAESKey, sCorpID);

            String msgSignature = request.getParameter("msg_signature");
            String timeStamp = request.getParameter("timestamp");
            String nonce = request.getParameter("nonce");
            String echostr = request.getParameter("echostr");
            log.info("企业微信加密签名: {},时间戳: {},随机数: {},加密的字符串: {}", msgSignature, timeStamp, nonce, echostr);
            sEchoStr = wxcpt.VerifyURL(msgSignature,
                    timeStamp,
                    nonce,
                    echostr);
            log.info("给企业微信返回的明文,{}", sEchoStr);
            log.info("=========验证URL有效性结束=========");

        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            return sEchoStr;
        }
    }

    /**
     * 企业微信回调参数解析
     *
     * @param request
     * @param body
     * @return
     */
    public static Map<String, String> getRequestParameter(HttpServletRequest request, String body, String sToken, String sCorpID, String sEncodingAESKey) {
        log.info("=========参数解析开始=========");
        Map<String, String> resultMap = null;

        try {
            WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(sToken, sEncodingAESKey, sCorpID);
            String msgSignature = request.getParameter("msg_signature");
            String timeStamp = request.getParameter("timestamp");
            String nonce = request.getParameter("nonce");
            String Encrypt = request.getParameter("Encrypt");

            log.info("企业微信加密签名: {},时间戳: {},随机数: {}, 加密的字符串: {}", msgSignature, timeStamp, nonce, body);
            String sMsg = wxcpt.DecryptMsg(msgSignature, timeStamp, nonce, body);
            resultMap = new HashMap<String, String>(16);
            resultMap = parseXmlToMap(sMsg, resultMap);
            log.info("decrypt密文转为map结果为{}", resultMap);
            log.info("=========参数解析结束=========");

        } catch (AesException e) {
            log.error(e.getMessage(),e);
            log.error("密文参数解析失败，错误原因请查看异常:{}", e.getMessage());
        } finally {
            return resultMap;
        }
    }

    /**
     * 将xml转换为Map。 支持xml标签多层嵌套，并以"."分隔多级标签（不包括根节点）。 不支持XML标签重复时的情况
     *
     * @param xml
     * @param map
     * @return
     */
    public static Map<String, String> parseXmlToMap(String xml, Map<String, String> map) {
        try {
            SAXReader reader = new SAXReader();
            Document doc = reader.read(new StringReader(xml));
            Element root = doc.getRootElement();
            String path = "";
            if (map.containsKey(root.getName().trim())) {
                path = map.get(root.getName().trim());
                map.remove(root.getName().trim());
            }
            for (Iterator i = root.elementIterator(); i.hasNext(); ) {
                Element element = (Element) i.next();
                if (element.isTextOnly()) {
                    if (path.length() > 0) {
                        map.put(path + element.getName().trim(), element.getTextTrim());
                    } else {
                        map.put(element.getName().trim(), element.getTextTrim());
                    }
                } else {
                    map.put(element.getName().trim(), path + element.getName().trim() + ".");
                    parseXmlToMap(element.asXML(), map);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

}
